const { useState,useEffect,Fragment } = React;
const X = 'X';
const O = 'O';



const WINNING_PATTERNS = [
    7,
    56,
    448, // Horizontal
    73,
    146,
    292, // Vertical
    273,
    84, // Cross
];


const Game = () => {
    const [player , setPlayer] = useState(X);
    const [patterns, setPatterns] = useState({ [X]: 0, [O]: 0 });
    const [winner, setWinner]  =  useState(null);
    const [rotated, setRotated] = useState(false);
    const [board, setBoard] = useState([
        [null, null, null],
        [null, null, null],
        [null, null, null],
    ]);

    handleOnClick = (i, j) => {
        if (null === board[i][j]) {
            const state = {
                board: [...board],
                player: player === X ? O : X,
                patterns: patterns,
            };

            state.board[i][j] = player;

            state.patterns[player] = state.patterns[player] |= Math.pow(
                2,
                i * 3 + j
            );

            state.winner = checkForWin(state.patterns);

            setBoard(state.board);
            setPlayer(state.player);
            setPatterns(state.patterns);
            setWinner(state.winner);

            if (state.winner || isBoardFull(board)) {
                setTimeout(() => {
                    setRotated(true);
                }, 1500);
            }
        }
    }

    handleOnPlayAgain = () => {
        setRotated(false);
        setTimeout(() => {
            setPlayer(X);
            setPatterns({[X]: 0, [O]: 0 });
            setWinner(null);
            setRotated(false);
            setBoard([
                [null, null, null],
                [null, null, null],
                [null, null, null],
            ]);
        }, 1000);
    }
   
  
    const checkForWin = (patterns) => {
        // Loop through all possible winning sets
        for (let i = 0; i < WINNING_PATTERNS.length; i++) {
            // Use bitwise AND to determind if the player's score
            // Holds a winning combination
            if ((WINNING_PATTERNS[i] & patterns[X]) === WINNING_PATTERNS[i])
                return X;
            if ((WINNING_PATTERNS[i] & patterns[O]) === WINNING_PATTERNS[i])
                return O;
        } // No winner
        return false;
    }

    const isBoardFull = (board) => {
        return !board.some((row, i) => {
            return row.some((col, j) => null === col);
        });
    }
    const getWinningPattern = () => {
        return WINNING_PATTERNS.find(
            (pattern) => (pattern & patterns[winner]) === pattern
        );
    }

    return (
        <div className={`game ${rotated ? "rotated" : ""}`} >
            <Results winner={winner} 
                draw={!winner && isBoardFull(board)}
                onPlayAgain={handleOnPlayAgain}
            ></Results>
            <Line show={winner} pattern={getWinningPattern()}></Line>
            <Board board={board} onClick={handleOnClick}></Board>
        </div>
    )
};

const Circle = () => {
    return (
        <svg className='pawn circle' viewBox="0 0 128 128">
            <path d="M64,16A48,48 0 1,0 64,112A48,48 0 1,0 64,16"></path>
        </svg>
    )
}


const Times = ()=> (
        <svg className="pawn times" viewBox= "0 0 128 128">
            <path d= "M16,16L112,112" ></path>
            <path d= "M112,16L16,112" ></path>
        </svg>
)

const Line = (props)=>{
    const { pattern,show } = props;

    d = ()=> {
        return {
            7: `M 0,5 H 100`,
            56: `M 0,50 H 100`,
            448: `M 0,95 H 100`,
            73: `M 5,0 V 100`,
            146: `M 50,0 V 100`,
            292: `M 95,0 V 100`,
            273: `M 0,0 L 100,100`,
            84: `M 100,0 L 0,100`,
        }[pattern];
    }
    return (
        <svg className={`line ${show ? "visible" : ""}`}  viewBox="0 0 100 100">
            <g>
                <path d={d()}></path>
            </g>
        </svg>
    )
}

const Cube = (props)=>{
    const {value,onClick} = props;
   
    return (
        <div className={`cube ${value ? "rotated" : ""}`}  
            ref={(ref) => (this.ref = ref)}
            onClick={onClick}
        >
            {
                ["top", "bottom", "left", "right", "front", "back"].map((face)=>(
                    <div className={face}>
                        {
                            face === 'back' && value === O && 
                            <Circle></Circle>
                        }
                        {
                            face === 'back' && value === X && 
                            <Times></Times>
                        }
                    </div>
                ))
            }
        </div>
    )
}


const Row = ({children}) => (<div className='row'>{children}</div>);

const Results = (props) => {
    const {winner,draw,onPlayAgain} = props;
    return (
        <div className="results">
            <div className="message">
                <div className="symbol">
                    {
                        winner === X && <Times></Times>
                    }
                    {
                        winner === O && <Circle></Circle>
                    }
                    {
                        draw && <Fragment>
                            <Times></Times>
                            <Circle></Circle>
                        </Fragment>
                    }
                </div>
                <div className="text">{winner ? "Wins!" : "Draw!"}</div>
            </div>
            <div className="replay" onClick={onPlayAgain}>"Play Again"</div>
        </div>
    )
}

const Board = (props)=>{
    const {board, onClick} = props;
    return (
        <div className="board">
            {
                board.map((row,i)=>(
                    <Row>
                        {
                            row.map((col,j)=><Cube value={col} onClick={()=>onClick(i,j)}></Cube>)
                        }
                    </Row>
                ))
            }
        </div>
    )

}


ReactDOM.render(React.createElement(Game, null), document.body);